﻿/*
 * XDevelopHelper
 *  @Author: XTST
 *  @Git: https://gitee.com/XTST/XUnityDevelopHelper
 *  Copyright © 2013-2018 Xiaotian Jin. All rights reserved.
 * */

using System;
using System.Collections.Generic;
using XDevelopHelper.Event.Base;

namespace XDevelopHelper.Event
{
    internal sealed partial class EventPool<T> where T : BaseEventArgs
    {
        #region Data

        // id-事件处理器映射
        private readonly Dictionary<int, EventHandler<T>> eventHandlers;
        // 事件触发队列
        private readonly Queue<TriggeredEvent> triggered;

        #endregion

        #region Constructor

        /// <summary>
        /// 构造一个默认的事件池
        /// </summary>
        public EventPool()
        {
            eventHandlers = new Dictionary<int, EventHandler<T>>();
            triggered = new Queue<TriggeredEvent>();
        }

        #endregion

        #region Event Manager

        /// <summary>
        /// 检查订阅事件
        /// </summary>
        /// <param name="id">id</param>
        /// <param name="handlerToCheck">需要检查的Handler</param>
        /// <returns></returns>
        public bool Check(int id, EventHandler<T> handlerToCheck)
        {
            if (handlerToCheck == null)
            {
                throw new Exception("Event handler is invalid. 事件处理器不可用。");
            }

            EventHandler<T> handlersAlreadyExists = null;
            if (!eventHandlers.TryGetValue(id, out handlersAlreadyExists))
            {
                // 无对应id
                return false;
            }

            if (handlersAlreadyExists == null)
            {
                // 无事件注册
                return false;
            }
            EventHandler<T> handler = null;
            for (int i = 0; i < handlersAlreadyExists.GetInvocationList().Length; i++)
            {
                handler = (EventHandler<T>)handlersAlreadyExists.GetInvocationList()[i];
                if (handler == handlerToCheck)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 订阅事件
        /// </summary>
        /// <param name="id">事件id</param>
        /// <param name="newHandler">新的handler</param>
        public void Subscribe(int id, EventHandler<T> newHandler)
        {
            if (newHandler == null)
            {
                throw new Exception("Event handler is invalid. 事件处理器不可用。");
            }

            EventHandler<T> eventHandler = null;
            if (Check(id, newHandler))
            {
                throw new Exception("EventSystem don't allow duplicate handler. 事件系统中同一个事件不允许使用重复处理函数");
            }
            else
            {
                eventHandler += newHandler;
                eventHandlers[id] = eventHandler;
            }
        }

        /// <summary>
        /// 取消订阅事件
        /// </summary>
        /// <param name="id">事件id</param>
        /// <param name="oldHander">要取消订阅的handler</param>
        public void Unsubscribe(int id, EventHandler<T> oldHander)
        {
            if (oldHander == null)
            {
                throw new Exception("Event handler is invalid. 事件处理器不可用。");
            }

            if (eventHandlers.ContainsKey(id))
            {
                eventHandlers[id] -= oldHander;
            }
        }

        /// <summary>
        /// 抛出事件
        /// </summary>
        public void Fire(object sender, T e)
        {
            TriggeredEvent newTriggered = new TriggeredEvent(sender, e);
            lock (triggered)
            {
                triggered.Enqueue(newTriggered);
            }
        }

        #endregion

        #region Eventhandler

        /// <summary>
        /// 处理事件
        /// </summary>
        /// <param name="sender"> 事件源 </param>
        /// <param name="e"> 事件参数 </param>
        private void HandleEvent(object sender, T e)
        {
            EventHandler<T> handler = null;
            if (eventHandlers.TryGetValue(e.EventId, out handler))
            {
                if (handler != null)
                {
                    handler.Invoke(sender, e);
                    return;
                }
            }
        }

        #endregion

        #region Updater

        public void Update()
        {
            while (triggered.Count > 0)
            {
                TriggeredEvent e;
                lock (triggered)
                {
                    e = triggered.Dequeue();
                }

                HandleEvent(e.Sender, e.EventArgs);
            }
        }

        #endregion
    }
}
